namespace cframework {
using System.Diagnostics;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System.Threading;
    using System.Linq;

    public class CommandLineTool
    {
        public static int ERROR_TIMEOUT = 1111111;

        public static int RunCommand(string workingDir, string program, string[] args, bool log = true)
        {
            using (Process p = new Process())
            {
                p.StartInfo.WorkingDirectory = workingDir;
                p.StartInfo.FileName = program;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.CreateNoWindow = true;
                string argsStr = string.Join(" ", args.Select(arg => "\"" + arg + "\""));
                p.StartInfo.Arguments = argsStr;
                if (log)
                {
                    UnityEngine.Debug.Log($"[BashUtil] run => {program} {argsStr}");
                }
                p.Start();
                p.WaitForExit();
                return p.ExitCode;
            }
        }


        public static (int ExitCode, string StdOut, string StdErr) RunCommand2(string program, string args, string workingDir, bool log = true)
        {
            return CmdExWithOutput(program, args, workingDir);
            //using (Process p = new Process())
            //{
            //    p.StartInfo.WorkingDirectory = workingDir;
            //    p.StartInfo.FileName = program;
            //    p.StartInfo.UseShellExecute = false;
            //    p.StartInfo.CreateNoWindow = true;
            //    p.StartInfo.RedirectStandardOutput = true;
            //    p.StartInfo.RedirectStandardError = true;
            //    string argsStr = args;
            //    p.StartInfo.Arguments = argsStr;
            //    if (log)
            //    {
            //        UnityEngine.Debug.Log($"[BashUtil] run => {program} {argsStr}");
            //    }
            //    p.Start();
            //    p.WaitForExit();

            //    string stdOut = p.StandardOutput.ReadToEnd();
            //    string stdErr = p.StandardError.ReadToEnd();
            //    return (p.ExitCode, stdOut, stdErr);
            //}
        }

        //       public static int Cmd(string command, string arguments)
        //{
        //	return CmdEx(command, arguments, "", false);
        //}

        //   public static int CmdWithOutput(string command, string arguments, ref string output, ref string outputError)
        //{
        //       return CmdExWithOutput(command, arguments, Application.dataPath + "/..", false, true, ref output, true, ref outputError);
        //}

        //   public static int CmdEx(string command, string arguments, string workDir, bool isWin)
        //{
        //	string output = null;
        //       string outputError = null;
        //       return CmdExWithOutput(command, arguments, Application.dataPath + "/../" + workDir, isWin, false, ref output, false, ref outputError);
        //}

        public static (int exitCode, string stdOut, string stdErr) CmdExWithOutput(string command, string arguments, string workDir, IDictionary<string, string> envVars = null)
        {
            string output;
            string outputError;

            int i = 0;
            while (i < 5)
            {
                i++;
                Process p = new Process();
                p.StartInfo.FileName = command;
                p.StartInfo.Arguments = arguments;
                p.StartInfo.WorkingDirectory = workDir;
                p.StartInfo.UseShellExecute = false;

                if (envVars != null)
                {
                    foreach (var entry in envVars)
                    {
                        if (p.StartInfo.EnvironmentVariables.ContainsKey(entry.Key))
                        {
                            p.StartInfo.EnvironmentVariables[entry.Key] = entry.Value;
                        }
                        else
                        {
                            p.StartInfo.EnvironmentVariables.Add(entry.Key, entry.Value);
                        }
                    }
                }
                if (p.StartInfo.UseShellExecute)
                {
                    //            p.StartInfo.RedirectStandardError=false;
                    //            p.StartInfo.RedirectStandardOutput=false;
                    //            p.StartInfo.RedirectStandardInput=false;
                }
                else
                {
                    p.StartInfo.RedirectStandardError = true;
                    p.StartInfo.RedirectStandardOutput = true;

                }

                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.ErrorDialog = true;
                p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                p.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
                p.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
                p.Start();

                string outStr = "";
                if (true)
                {
                    try
                    {

                        p.OutputDataReceived += (o, ar) =>
                        { outStr += ar.Data + "\n"; };
                        p.BeginOutputReadLine();
                        //System.Text.StringBuilder outputBuilder = new System.Text.StringBuilder();
                        //while (!p.StandardOutput.EndOfStream)
                        //{
                        //	string line = p.StandardOutput.ReadLine();
                        //	outputBuilder.AppendLine(line);
                        //}

                        //output = outputBuilder.ToString();
                    }
                    catch (System.Exception e)
                    {
                        output = e.Message;
                    }
                }
                //else
                //{
                //	if(!p.WaitForExit(10000))
                //          {
                //              if(i >= 5)
                //              {
                //                  return ERROR_TIMEOUT;
                //              }

                //              Thread.Sleep(2000);
                //              continue;
                //          }
                //}

                string errOut = "";
                try
                {

                    p.ErrorDataReceived += (o, ar) =>
                    {
                        errOut += ar.Data + "\n";
                    };
                    p.BeginErrorReadLine();

                    //outputError = p.StandardError.ReadToEnd();
                }
                catch (System.Exception e)
                {
                    outputError = e.Message;
                }

                //while (!p.HasExited)
                //{
                //    continue;
                //}

                p.WaitForExit();

                output = outStr;
                outputError = errOut;

                return (p.ExitCode, outStr, errOut);

            }

            return (ERROR_TIMEOUT, null, null);
        }
    }
}